use std::{fs::File, io::Read};

use anyhow::Context;
use base64::{engine::GeneralPurpose, prelude::BASE64_STANDARD, Engine};

use crate::Base64Format;

pub fn base64_encode(input: &str, format: &Base64Format) -> anyhow::Result<String> {
    let buf = read_input(input)?;

    let engine = get_base64_engine(format);
    Ok(engine.encode(&buf))
}
pub fn base64_decode(input: &str, format: &Base64Format) -> anyhow::Result<String> {
    let buf = read_input(input)?;

    let engine = get_base64_engine(format);
    let decoded_bytes = engine
        .decode(&buf)
        .context("Failed to decode base64 string...");
    String::from_utf8(decoded_bytes?).context("Failed to convert bytes to string...")
}

// 抽取选中代码到新函数
fn read_input(input: &str) -> anyhow::Result<String> {
    let mut reader: Box<dyn Read> = if input == "-" {
        Box::new(std::io::stdin())
    } else {
        Box::new(File::open(input)?)
    };

    let mut buf = String::new();
    reader.read_to_string(&mut buf)?;
    Ok(buf.trim().to_string())
}

fn get_base64_engine(format: &Base64Format) -> GeneralPurpose {
    match format {
        Base64Format::STANDARD => {
            eprintln!("Using standard base64 format...");
            BASE64_STANDARD
        }
        Base64Format::URLSAFE => {
            eprintln!("Using URL safe base64 format...");
            base64::engine::general_purpose::URL_SAFE
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_base64_encode() {
        let input = "assets/encode.txt";
        let expected = "SGVsbG8sIFdvcmxkIQ==";

        let result = base64_encode(input, &Base64Format::STANDARD).unwrap();

        assert_eq!(result, expected);
    }

    #[test]
    fn test_base64_decode() {
        let input = "assets/decode.txt";
        let expected = "Hello, World!";
        let result = base64_decode(input, &Base64Format::STANDARD).unwrap();
        assert_eq!(result, expected);
    }
}
